//
//  YSNetworking.m
//  YSKitExample
//
//  Created by Kyson on 2017/6/16.
//  Copyright © 2017年 YangShen. All rights reserved.
//

#import "YSNetworking.h"
#import <AFNetworking/AFNetworking.h>
#import <AFNetworking/AFHTTPSessionManager.h>
#import <AFNetworking/AFNetworkActivityIndicatorManager.h>

static BOOL ys_shouldCallbackOnCancelRequest = YES; ///< 请求取消，是否回调
static NSString *ys_privateNetworkBaseUrl = nil; ///< BaseUrl
static NSTimeInterval ys_timeout = 60.f;    ///< 超时时间
static BOOL ys_isEnableInterfaceDebug = NO; ///< 是否开启Debug
static NSDictionary *ys_httpHeaders = nil;  ///< 头信息
static YSResponseType ys_responseType = YSResponseTypeJSON;
static YSRequestType  ys_requestType  = YSRequestTypeJSON;
static YSNetworkStatus ys_networkStatus = YSNetworkStatusUnknown;
static NSMutableArray *ys_requestTasks; ///< 所有请求

typedef NS_ENUM(NSUInteger, YSHTTPMethodType) {
    YSHTTPMethodTypeGet  = 1, // Get
    YSHTTPMethodTypePost = 2  // Post
};

@implementation YSNetworking

+ (NSString *)baseUrl {
    return ys_privateNetworkBaseUrl;
}

+ (void)updateBaseUrl:(NSString *)baseUrl {
    ys_privateNetworkBaseUrl = baseUrl;
}

+ (void)setTimeout:(NSTimeInterval)timeout {
    ys_timeout = timeout;
}

+ (void)enableInterfaceDebug:(BOOL)isDebug {
    ys_isEnableInterfaceDebug = isDebug;
}

+ (void)configCommonHttpHeaders:(NSDictionary *)httpHeaders {
    ys_httpHeaders = httpHeaders;
}

+ (void)configRequestType:(YSRequestType)requestType
             responseType:(YSResponseType)responseType
  callbackOnCancelRequest:(BOOL)shouldCallbackOnCancelRequest {
    ys_requestType = requestType;
    ys_responseType = responseType;
    ys_shouldCallbackOnCancelRequest = shouldCallbackOnCancelRequest;
}

+ (NSMutableArray *)allTasks {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (ys_requestTasks == nil) {
            ys_requestTasks = [[NSMutableArray alloc] init];
        }
    });
    return ys_requestTasks;
}

+ (void)cancelAllRequest {
    @synchronized(self) {
        [[self allTasks] enumerateObjectsUsingBlock:^(YSURLSessionTask * _Nonnull task, NSUInteger idx, BOOL * _Nonnull stop) {
            if ([task isKindOfClass:[YSURLSessionTask class]]) {
                [task cancel];
            }
        }];
        [[self allTasks] removeAllObjects];
    };
}

+ (void)cancelRequestWithURL:(NSString *)url {
    if (!url) return;
    @synchronized(self) {
        [[self allTasks] enumerateObjectsUsingBlock:^(YSURLSessionTask * _Nonnull task, NSUInteger idx, BOOL * _Nonnull stop) {
            if ([task isKindOfClass:[YSURLSessionTask class]]
                && [task.currentRequest.URL.absoluteString hasSuffix:url]) {
                [task cancel];
                [[self allTasks] removeObject:task];
                return;
            }
        }];
    };
}

#pragma mark -网络请求
+ (YSURLSessionTask *)GET:(NSString *)url
                   params:(NSDictionary *)params
                  success:(YSResponseSuccess)success
                  failure:(YSResponseFail)failure {
    return [self GET:url params:params progress:nil success:success failure:failure];
}

+ (YSURLSessionTask *)GET:(NSString *)url
                   params:(NSDictionary *)params
                 progress:(YSDownloadProgress)progress
                  success:(YSResponseSuccess)success
                  failure:(YSResponseFail)failure {
    return [self ys_requestWithUrl:url httpMethodType:YSHTTPMethodTypeGet params:params progress:progress success:success failure:failure];
}

+ (YSURLSessionTask *)POST:(NSString *)url
                    params:(NSDictionary *)params
                   success:(YSResponseSuccess)success
                   failure:(YSResponseFail)failure {
    return [self POST:url params:params progress:nil success:success failure:failure];
}

+ (YSURLSessionTask *)POST:(NSString *)url
                    params:(NSDictionary *)params
                  progress:(YSDownloadProgress)progress
                   success:(YSResponseSuccess)success
                   failure:(YSResponseFail)failure {
    return [self ys_requestWithUrl:url httpMethodType:YSHTTPMethodTypePost params:params progress:progress success:success failure:failure];
}

+ (YSURLSessionTask *)ys_requestWithUrl:(NSString *)url
                         httpMethodType:(YSHTTPMethodType)type
                                 params:(NSDictionary *)params
                               progress:(YSDownloadProgress)progress
                                success:(YSResponseSuccess)success
                                failure:(YSResponseFail)failure {
    NSString *absoluteString = [self absoluteUrlWithPath:url];
    if (![NSURL URLWithString:absoluteString]) {
        YSNetLog(@"=========== URLString无效，无法生成URL，请检查后再试! ===========");
        return nil;
    }
    
    AFHTTPSessionManager *manager = [self manager];
    YSURLSessionTask *task = nil;
    switch (type) {
        case YSHTTPMethodTypeGet: {
            task = [manager GET:absoluteString parameters:params progress:^(NSProgress * _Nonnull downloadProgress) {
                if (progress) progress(downloadProgress.completedUnitCount, downloadProgress.totalUnitCount);
            } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                if ([[self allTasks] containsObject:task]) [[self allTasks] removeObject:task];
                success(responseObject);
            } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                if ([[self allTasks] containsObject:task]) [[self allTasks] removeObject:task];
                failure(error);
            }];
            break;
        }
        case YSHTTPMethodTypePost: {
            task = [manager POST:absoluteString parameters:params progress:^(NSProgress * _Nonnull uploadProgress) {
                if (progress) progress(uploadProgress.completedUnitCount, uploadProgress.totalUnitCount);
            } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                if ([[self allTasks] containsObject:task]) [[self allTasks] removeObject:task];
                success(responseObject);
            } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                if ([[self allTasks] containsObject:task]) [[self allTasks] removeObject:task];
                failure(error);
            }];
            break;
        }
    }
    if (task) [[self allTasks] addObject:task];
    return task;
}

+ (YSURLSessionTask *)Upload:(NSString *)url
               uploadingFile:(NSString *)uploadingFile
                    progress:(YSUploadProgress)progress
                     success:(YSResponseSuccess)success
                     failure:(YSResponseFail)failure {
    NSString *absoluteString = [self absoluteUrlWithPath:url];
    if (![NSURL URLWithString:absoluteString]) {
        YSNetLog(@"URLString无效，无法生成URL，请检查后再试!");
        return nil;
    }
    
    if (![NSData dataWithContentsOfFile:uploadingFile]) {
        YSNetLog(@"uploadingFile无效，请检查文件是否存在!");
        return nil;
    }
    
    AFHTTPSessionManager *manager = [self manager];
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:absoluteString]];
    YSURLSessionTask *task = nil;
    task = [manager uploadTaskWithRequest:request fromData:[NSData dataWithContentsOfFile:uploadingFile] progress:^(NSProgress * _Nonnull uploadProgress) {
        if (progress) progress(uploadProgress.completedUnitCount, uploadProgress.totalUnitCount);
    } completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
        if (error) {
            if ([[self allTasks] containsObject:task]) [[self allTasks] removeObject:task];
            failure(error);
        } else {
            if ([[self allTasks] containsObject:task]) [[self allTasks] removeObject:task];
            success(responseObject);
        }
    }];
    
    if (task) [[self allTasks] addObject:task];
    return task;
}

+ (YSURLSessionTask *)UploadImage:(UIImage *)image
                              url:(NSString *)url
                         filename:(NSString *)filename
                             name:(NSString *)name
                         mimeType:(NSString *)mimeType
                       parameters:(NSDictionary *)parameters
                         progress:(YSUploadProgress)progress
                          success:(YSResponseSuccess)success
                          failure:(YSResponseFail)failure {
    NSString *absoluteString = [self absoluteUrlWithPath:url];
    if (![NSURL URLWithString:absoluteString]) {
        YSNetLog(@"URLString无效，无法生成URL，请检查后再试!");
        return nil;
    }
    
    if (!image) {
        YSNetLog(@"图片不存在，请检查！");
        return nil;
    }
    
    AFHTTPSessionManager *manager = [self manager];
    YSURLSessionTask *task = [manager POST:absoluteString parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        NSData *imageData = UIImageJPEGRepresentation(image, 1);
        
        NSString *imageFileName = filename;
        if (filename == nil || ![filename isKindOfClass:[NSString class]] || filename.length == 0) {
            NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
            formatter.dateFormat = @"yyyyMMddHHmmss";
            NSString *str = [formatter stringFromDate:[NSDate date]];
            imageFileName = [NSString stringWithFormat:@"%@.jpg", str];
        }
        
        // 上传图片，以文件流的格式
        [formData appendPartWithFileData:imageData name:name fileName:imageFileName mimeType:mimeType];
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        if (progress) {
            progress(uploadProgress.completedUnitCount, uploadProgress.totalUnitCount);
        }
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        [[self allTasks] removeObject:task];
        success(responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        if ([[self allTasks] containsObject:task]) [[self allTasks] removeObject:task];
        failure(error);
    }];
    
    if (task) [[self allTasks] addObject:task];
    return task;
}

+ (YSURLSessionTask *)DownLoad:(NSString *)url
                    saveToPath:(NSString *)saveToPath
                      progress:(YSDownloadProgress)progressBlock
                       success:(YSResponseSuccess)success
                       failure:(YSResponseFail)failure {
    NSString *absoluteString = [self absoluteUrlWithPath:url];
    if (![NSURL URLWithString:absoluteString]) {
        YSNetLog(@"URLString无效，无法生成URL，请检查后再试!");
        return nil;
    }
    
    NSURLRequest *downloadRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:absoluteString]];
    AFHTTPSessionManager *manager = [self manager];
    YSURLSessionTask *task = nil;
    
    task = [manager downloadTaskWithRequest:downloadRequest progress:^(NSProgress * _Nonnull downloadProgress) {
        if (progressBlock) {
            progressBlock(downloadProgress.completedUnitCount, downloadProgress.totalUnitCount);
        }
    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        return [NSURL URLWithString:saveToPath];
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        if ([[self allTasks] containsObject:task]) [[self allTasks] removeObject:task];
        if (error == nil) {
            success(error);
        } else {
            failure(error);
        }
    }];
    
    if (task) [[self allTasks] addObject:task];
    return task;
}

#pragma mark - Private
/**
 *  拼接绝对路径
 */
+ (NSString *)absoluteUrlWithPath:(NSString *)path {
    if (path == nil || path.length == 0) return @"";
    if ([self baseUrl] == nil || [[self baseUrl] length] == 0) return path;
    
    NSString *absoluteUrl = path;
    if (![path hasPrefix:@"http://"] && ![path hasPrefix:@"https://"]) {
        if ([[self baseUrl] hasSuffix:@"/"]) {
            if ([path hasPrefix:@"/"]) {
                NSMutableString * mutablePath = [NSMutableString stringWithString:path];
                [mutablePath deleteCharactersInRange:NSMakeRange(0, 1)];
                absoluteUrl = [NSString stringWithFormat:@"%@%@",[self baseUrl], mutablePath];
            }else {
                absoluteUrl = [NSString stringWithFormat:@"%@%@",[self baseUrl], path];
            }
        }else {
            if ([path hasPrefix:@"/"]) {
                absoluteUrl = [NSString stringWithFormat:@"%@%@",[self baseUrl], path];
            }else {
                absoluteUrl = [NSString stringWithFormat:@"%@/%@",[self baseUrl], path];
            }
        }
    }
    return [self ys_URLEncode:absoluteUrl];
}

+ (NSString *)ys_URLEncode:(NSString *)url {
    if ([[[UIDevice currentDevice] systemVersion] compare:@"9.0"] != NSOrderedAscending) {
        return [url stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    } else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        return [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
#pragma clang diagnostic pop
    }
    return url;
}


/**
 *  创建一个AFHTTPSessionManager
 */
+ (AFHTTPSessionManager *)manager {
    // 开启转圈圈
    [AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
    
    AFHTTPSessionManager *manager = nil;
    if ([self baseUrl] != nil) {
        manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:[self baseUrl]]];
    } else {
        manager = [AFHTTPSessionManager manager];
    }
    
    switch (ys_requestType) {
        case YSRequestTypeJSON:
            manager.requestSerializer = [AFJSONRequestSerializer serializer];
            break;
        case YSRequestTypePlainTest:
            manager.requestSerializer = [AFHTTPRequestSerializer serializer];
            break;
        default: break;
    }
    
    switch (ys_responseType) {
        case YSResponseTypeJSON: {
            manager.responseSerializer = [AFJSONResponseSerializer serializer];
            break;
        }
        case YSResponseTypeXML: {
            manager.responseSerializer = [AFXMLParserResponseSerializer serializer];
            break;
        }
        case YSResponseTypeData: {
            manager.responseSerializer = [AFHTTPResponseSerializer serializer];
            break;
        }
        default: break;
    }
    
    // 设置超时时间
    manager.requestSerializer.timeoutInterval = ys_timeout;
    manager.requestSerializer.stringEncoding = NSUTF8StringEncoding;
    
    for (NSString *key in ys_httpHeaders) {
        if (ys_httpHeaders[key] != nil) {
            [manager.requestSerializer setValue:ys_httpHeaders[key] forHTTPHeaderField:key];
        }
    }
    
    manager.responseSerializer.acceptableContentTypes =
    [NSSet setWithArray:@[@"application/json",
                          @"text/html",
                          @"text/json",
                          @"text/plain",
                          @"text/javascript",
                          @"text/xml",
                          @"image/*"]];
    
    [self detectNetwork];
    
    return manager;
}

+ (void)detectNetwork {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        AFNetworkReachabilityManager *reachabilityManager = [AFNetworkReachabilityManager sharedManager];
        [reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
            if (status == AFNetworkReachabilityStatusNotReachable){
                ys_networkStatus = YSNetworkStatusNotReachable;
                YSNetLog(@"无网络");
            }else if (status == AFNetworkReachabilityStatusUnknown){
                ys_networkStatus = YSNetworkStatusUnknown;
                YSNetLog(@"未知网络");
            }else if (status == AFNetworkReachabilityStatusReachableViaWWAN){
                ys_networkStatus = YSNetworkStatusReachableViaWWAN;
                YSNetLog(@"手机2/3/4G");
            }else if (status == AFNetworkReachabilityStatusReachableViaWiFi){
                ys_networkStatus = YSNetworkStatusReachableViaWiFi;
                YSNetLog(@"Wifi");
            }
        }];
        [reachabilityManager startMonitoring];
    });
}

// 判断网络类型
+ (YSNetworkStatus)getNetworkStates {
    return ys_networkStatus;
}

@end
